package de.ur.iw.wiki;

import java.util.ArrayList;

public class WikiPage implements LinkCollector {

	private static String language = WikiConfig.LANGUAGE;

	/**
	 * an URL to a xml-version of a wiki page (replace %1 with the wiki site
	 * name)
	 */
	public static String WIKI_URL = "http://"
			+ language
			+ ".wikipedia.org/w/api.php?action=query&prop=revisions&titles=%1&rvprop=content&format=xml";
	/**
	 * an URL to a category webpage (replace %1 with the category you want)
	 */
	public static String WIKI_CATEGORY_URL = "http://" + language
			+ ".wikipedia.org/wiki/%1";

	/**
	 * an URL to a random xml-version of a wiki page
	 */
	public static String RANDOM_URL = "http://" + language
			+ ".wikipedia.org/w/api.php?action=query&list=random&format=xml";
	/**
	 * regular expression how a link is written in wiki-style
	 */
	public static final String LINK_REGEX = "\\[\\[[^\\]\\]]*\\]\\]";
	/**
	 * seperator that seperates the name and link in a wiki-link
	 */
	public static final String LINK_SEPERATOR = "\\|";
	/**
	 * xml-tag containing the title of the page
	 */
	public static final String PAGE_TAG = "page";
	/**
	 * xml-tag containing the content of the page
	 */
	public static final String XML_TAG = "rev";
	/**
	 * seperator in links for cross-references (like categories, other languages
	 * ...)
	 */
	public static final String CROSS_REFERENCE_SEPERATOR = ":";

	public static final String CATEGORY_REGEX = "Kategorie:[^\"]*";
	public static final String PAGE_REGEX_REPLACEMENT = "title=\"";
	public static final String PAGE_REGEX = PAGE_REGEX_REPLACEMENT + "[^\"]*";

	private String name = "null";

	private ArrayList<Link> categories = new ArrayList<Link>();
	private ArrayList<Link> files = new ArrayList<Link>();
	private ArrayList<Paragraph> paragraphs = new ArrayList<Paragraph>();

	private Paragraph description;

	private String content;

	public WikiPage(String name) {
		super();
		this.name = name;
		description = new Paragraph(name, this);
		paragraphs.add(description);
	}

	public WikiPage() {
		super();
		this.name = "";
		description = new Paragraph("", this);
		paragraphs.add(description);
	}

	public static void setLanguage(String lang) {
		language = lang;
		WIKI_URL = "http://"
				+ language
				+ ".wikipedia.org/w/api.php?action=query&prop=revisions&titles=%1&rvprop=content&format=xml";
		RANDOM_URL = "http://"
				+ language
				+ ".wikipedia.org/w/api.php?action=query&list=random&format=xml";
	}

	public static String getLanguage() {
		return language;
	}

	public void setName(String name) {
		this.name = name;
		description.setName(name);
	}

	public String getName() {
		return name;
	}

	public String getUrl() {
		return WIKI_URL.replace("%1", name.replaceAll(" ", "_"));
	}

	public Link getRandomArticle() {
		ArrayList<Link> links = getAllLinks();
		int rand = (int) (Math.random() * links.size());
		return links.get(rand);
	}

	private ArrayList<Link> getAllLinks() {
		ArrayList<Link> result = new ArrayList<Link>();
		for (int i = 0; i < paragraphs.size(); i++) {
			result.addAll(paragraphs.get(i).getAllLinks());
		}
		return result;
	}

	public Link getRandomWeightedArticle() {
		double total = getTotalWeight();
		double rand = Math.random() * total;
		Link l = getWeightedLinkAt(rand);
		return l;
	}

	private Link getWeightedLinkAt(double position) {
		ArrayList<Link> links = getAllLinks();
		links.addAll(categories);
		links.addAll(files);
		double weight = 0;
		for (int i = 0; i < links.size(); i++) {
			weight += links.get(i).getWeight();
			if (weight >= position) {
				return links.get(i);
			}
		}
		return getRandomArticle();
	}

	private double getTotalWeight() {
		ArrayList<Link> links = getAllLinks();
		links.addAll(categories);
		links.addAll(files);
		double result = 0;
		for (int i = 0; i < links.size(); i++) {
			result += links.get(i).getWeight();
		}
		return result;
	}

	public String getRandomCategory() {
		int rand = (int) (Math.random() * categories.size());
		return categories.get(rand).getName();
	}

	/**
	 * @deprecated use {@link #getRandomWeightedArticle() getRandomWeightedArticle} instead
	 * @return
	 */
	public String getRandomUrl() {
		double category = Math.random();
		String result = null;
		if (category < Settings.getDouble(
				Settings.KEY_CATEGORIES_WEIGHT, 0)) {
			result = getUrlFromArticle(getRandomCategory());
			if (result == null) {
				return getUrlFromArticle(getRandomArticle().toString());
			}
		} else {
			result = getUrlFromArticle(getRandomArticle().toString());
			if (result == null) {
				return getUrlFromArticle(getRandomCategory());
			}
		}
		return result;
	}

	public static String getUrlFromArticle(String name) {
		return WIKI_URL.replace("%1", name.replaceAll(" ", "_"));
	}

	@Override
	public boolean equals(Object o) {
		if (o instanceof WikiPage) {
			WikiPage other = (WikiPage) o;
			return other.getName().equals(getName());
		}
		return super.equals(o);
	}

	@Override
	public String toString() {
		return getName();
	}

	public void weight(Weighter w) {
		// weight links
		ArrayList<Link> links = getAllLinks();
		for (int i = 0; i < links.size(); i++) {
			w.weight(links.get(i));
		}

		// weight categories
		links = categories;
		for (int i = 0; i < links.size(); i++) {
			w.weight(links.get(i));
		}

		// weight files
		links = files;
		for (int i = 0; i < links.size(); i++) {
			w.weight(links.get(i));
		}
	}

	public void addArticleToDescription(Link link) {
		description.add(link);
	}

	public void addArticlesToDescription(ArrayList<Link> links) {
		for (int i = 0; i < links.size(); i++) {
			addArticleToDescription(links.get(i));
		}
	}

	public void addCategory(Link category) {
		categories.add(category);
	}

	public int getCategoryCount() {
		return categories.size();
	}

	public Link getCategoryAt(int pos) {
		return categories.get(pos);
	}

	public int getParagraphCount() {
		return paragraphs.size();
	}

	public Paragraph getParagraphAt(int pos) {
		return paragraphs.get(pos);
	}

	public int size() {
		return getAllLinks().size() + categories.size() + files.size();
	}

	public void addFile(Link link) {
		files.add(link);
	}

	public int getFileCount() {
		return files.size();
	}

	public Link getFileAt(int pos) {
		return files.get(pos);
	}

	@Override
	public void addParagraph(LinkCollector paragraph) {
		if (paragraph instanceof Paragraph) {
			paragraphs.add((Paragraph) paragraph);
		}
	}

	@Override
	public void add(Link link) {
		addArticleToDescription(link);
	}

	public int indexOf(LinkCollector paragraph) {
		return paragraphs.indexOf(paragraph);
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

}
